package cn.xopencode.security.user.core.interceptor;
import cn.xopencode.common.framework.enums.UserTypeEnum;
import cn.xopencode.common.framework.exception.util.ServiceExceptionUtil;
import cn.xopencode.common.framework.util.CollectionUtils;
import cn.xopencode.common.framework.util.HttpUtil;
import cn.xopencode.common.framework.vo.CommonResult;
import cn.xopencode.oss.rpc.permission.PermissionRpc;

import cn.xopencode.oss.rpc.permission.dto.PermissionCheckDTO;
import cn.xopencode.security.user.core.context.UserSecurityContext;
import cn.xopencode.security.user.core.context.UserSecurityContextHolder;
import cn.xopencode.oss.rpc.oauth.OAuth2Rpc;
import cn.xopencode.oss.rpc.oauth.dto.OAuth2AccessTokenRespDTO;
import cn.xopencode.web.core.util.CommonWebUtil;
import cn.xopencode.security.annotations.RequiresAuthenticate;
import cn.xopencode.security.annotations.RequiresPermissions;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;

import static cn.xopencode.common.framework.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED;
public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
    @DubboReference(version = "${dubbo.consumer.OAuth2Rpc.version}")
    private OAuth2Rpc oauth2Rpc;
    @DubboReference(version = "${dubbo.consumer.PermissionRpc.version}")
    private PermissionRpc permissionRpc;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 获得访问令牌
        String userId = this.obtainUserId(request);
        // 校验认证
        return  this.checkAuthentication((HandlerMethod) handler, userId);
    }
    /**
     *
     * @param request
     * @return
     */
    private String obtainUserId(HttpServletRequest request) {
        String accessToken = HttpUtil.obtainAuthorization(request);
        String userId = null;
        if (accessToken != null) {
            CommonResult<OAuth2AccessTokenRespDTO> checkAccessTokenResult = oauth2Rpc.checkAccessToken(accessToken);
            checkAccessTokenResult.checkError();
            // 获得用户编号
            userId = checkAccessTokenResult.getData().getUserId();
            // 设置到 Request 中
            CommonWebUtil.setUserId(request, userId);
            CommonWebUtil.setUserType(request, UserTypeEnum.USER.getValue());
            // 设置到UserSecurityContextHolder中
            UserSecurityContext userSecurityContext = new UserSecurityContext().setUserId(userId);
            UserSecurityContextHolder.setContext(userSecurityContext);
        }
        return userId;
    }
    /**
     * 登录和权限校验
     * @param handlerMethod
     * @param userId
     */
    private boolean checkAuthentication(HandlerMethod handlerMethod, String userId) {
        boolean requiresAuthenticate = false;
        if (handlerMethod.hasMethodAnnotation(RequiresAuthenticate.class)
                || handlerMethod.hasMethodAnnotation(RequiresPermissions.class)) { // 如果需要权限验证，也认为需要认证
            requiresAuthenticate = true;
        }
        if (requiresAuthenticate && userId == null) {
            throw ServiceExceptionUtil.exception(UNAUTHORIZED);
        }else if(handlerMethod.hasMethodAnnotation(RequiresPermissions.class)){
            //TODo：根據userID獲取用戶的職位id，先从Redis缓存中根据userID、positionID加载PermissionCheckDTO实体进行验证，如果存在且isChecked为true则直接权限校验通过，如果没有缓存信息则需要调用oss-service提供的接口获取positionID
            PermissionCheckDTO checkDTO=  permissionRpc.get(userId);
            String  positionId=null;
            if(checkDTO!=null){
                if(checkDTO.isChecked()){
                    return true;
                }
                positionId=checkDTO.getPositionId();
            }


            //要校驗的權限集合
            RequiresPermissions requiresPermissions = handlerMethod.getMethodAnnotation(RequiresPermissions.class);
            if (requiresPermissions == null) {
                return true;
            }
            String[] permissions = requiresPermissions.value();
            if (CollectionUtils.isEmpty(permissions)) {
                return true;
            }
            // 用户权限验证
            checkDTO = new PermissionCheckDTO().setPositionId(positionId).setPermissions(Arrays.asList(permissions)).setUserId(userId);//将含有userID、positionId、Collection<String> permissions的对象存入缓存，供下次使用
            CommonResult<Boolean> pass= permissionRpc.checkPermission(checkDTO);
            pass.checkError();
            if (!pass.getData()) {//如果權限檢查失敗直接返回
                return false;
            }else{//TODo：将包括用户ID、职务ID、需要校验的权限集合、是否已校验通过等信息的PermissionCheckDTO缓存进Redis
                checkDTO.setChecked(true);
                permissionRpc.set(checkDTO);
            }
        }
        return true;
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 清空 SecurityContext
        UserSecurityContextHolder.clear();
    }

}
